/***************************************************************************
 *   Copyright (C) 2008 by Chris Bornholdt   *
 *   chris.bornholdt@gmail.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
 
#ifndef _THREAD_STORAGE_HPP_
#define _THREAD_STORAGE_HPP_

#include <QMutexLocker>
#include <QThreadStorage>
#include <QVector>

//stores index of object for each given thread
template<class Type>
struct StorageWrapper;

template<class Type>
class ThreadStorage
{
	public:	
		friend class StorageWrapper<Type>;
		
		ThreadStorage() {}
		~ThreadStorage() {}
		
		Type& instance()
		{
			QMutexLocker lock(&mutex_);
			if(!storage_.hasLocalData())
			{
				int i;
				for(i = 0; i < instances_.size(); ++i)
					if(instances_[i].second == false) break;
				if(i == instances_.size())	//all instances are owned
					instances_.resize(instances_.size() + 1);	//add an element
				storage_.setLocalData(new StorageWrapper<Type>(*this, i));
			}	
			
			return (*storage_.localData())();
		}
		const Type& instance() const
		{
			QMutexLocker lock(&mutex_);	
			if(!storage_.hasLocalData())
			{
				int i;
				for(i = 0; i < instances_.size(); ++i)
					if(instances_[i].second == false) break;
				if(i == instances_.size())	//all instances are owned
					instances_.resize(instances_.size() + 1);	//add an element
				storage_.setLocalData(new StorageWrapper<Type>(*this, i));
			}	
			
			return (*storage_.localData())();
		}
		
		void release()	//releases resource owned by this thread
		{
			QMutexLocker lock(&mutex_);
			if(storage_.hasLocalData())
				delete storage_.localData();
		}
		
	private:
		mutable QVector<std::pair<Type, bool> > instances_;
		mutable QThreadStorage<StorageWrapper<Type> *> storage_;
		
		QMutex mutex_;
};

template<class Type>
struct StorageWrapper
{
	StorageWrapper(ThreadStorage<Type>& owner, int i) :
		storage(owner), index(i)
	{
		assert(storage.instances_[index].second == false);
		storage.instances_[index].second = true;
	}
	
	~StorageWrapper()
	{	storage.instances_[index].second = false;		}
		
	Type& operator()()
	{	return storage.instances_[index].first;	}
	
	const Type& operator()() const
	{	return storage.instance_[index].first;	}
	
	const ThreadStorage<Type>& storage;
	int index;
};
	

#endif
